﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Dycox.Workflows
{
    public abstract class ThreadLockOperation : TransitionOperation
    {
        public ThreadLockOperation(string lockName)
        {
            if (string.IsNullOrWhiteSpace(lockName))
                throw new ArgumentNullException("lockName");

            _lockName = lockName;
        }

        private string _lockName;

        public string LockName
        {
            get { return _lockName; }
        }


        protected override void PerformCore(TransitionOperationArguments args)
        {

            PerformLockOperation(GetLock(args.Context.Process), args);
        }

        internal ThreadLock GetLock(WFProcess process)
        {
            Workflow wf = WorkflowManager.GetWorkflow(process.WorkflowName);
            return wf.ThreadLocks.GetLock(_lockName);
        }

        protected abstract void PerformLockOperation(ThreadLock threadLock, TransitionOperationArguments args);

        // 在同一个变换上不应该有多个相同类型的锁操作，所以以下代码注释掉。
        //protected internal override string Token
        //{
        //    get
        //    {
        //        return _lockName;
        //    }
        //}
    }

    public sealed class ThreadLockSetOperation : ThreadLockOperation
    {
        public ThreadLockSetOperation(string lockName)
            : base(lockName)
        {

        }

        protected override void PerformLockOperation(ThreadLock threadLock, TransitionOperationArguments args)
        {
            if (args.NewStep == null)
                throw new InvalidOperationException("Thread lock set operation cannot only apply on new step, and was not provided.");
            threadLock.Set(args.NewStep.Step);
        }

        public override TransitionTypes SupportedTransitionTypes
        {
            get { return TransitionTypes.Normal | TransitionTypes.NoMoreStep; }
        }
    }

    public sealed class ThreadLockReleaseOperation : ThreadLockOperation
    {
        public ThreadLockReleaseOperation(string name)
            : base(name)
        {

        }

        protected override void PerformLockOperation(ThreadLock threadLock, TransitionOperationArguments args)
        {
            threadLock.Release(args.Context.Step);

            //foreach (var thread in args.Context.Process.ThreadsInternal)
            //{
            //    if (ThreadLock.IsThreadSychronizing(thread, threadLock) && !ThreadLock.IsThreadLocked(thread, threadLock))
            //    {
            //        threadLock.ExitSynchronizing(thread);
            //    }
            //}
        }

        public override TransitionTypes SupportedTransitionTypes
        {
            get { return TransitionTypes.Normal | TransitionTypes.NoMoreStep | TransitionTypes.ExitStage; }
        }
    }

    public sealed class ThreadLockWaitOperation : ThreadLockOperation
    {
        public ThreadLockWaitOperation(string name)
            : base(name)
        {
        }

        protected override void PerformLockOperation(ThreadLock threadLock, TransitionOperationArguments args)
        {
            threadLock.Wait(args.Context.Step);
        }

        public override TransitionTypes SupportedTransitionTypes
        {
            get { return TransitionTypes.ExitStage; }
        }
    }
}
